using System;
using System.Collections.Generic;
using TTXNA.src.Engine.Graphics;
using TTXNA.src.Util;
using Microsoft.Xna.Framework;
using TTXNA.src.Engine.Industries;
using TTXNA.src.Engine.Stations;
using TTXNA.src.Engine.World;

namespace TTXNA.src.Engine.Terrain
{
    public enum LandType { Grass, Farmland, Water, Road, Rail, Canal, Building };
    public enum SlopeType { Flat, FlatSlope, SlantSlope, CornerSlope, DoubleCornerSlope, Invalid };

    public class Tile
    {
        private static Dictionary<int, int> table = new Dictionary<int, int>();

        private DDDCoordinate coord;

        private List<GameObject> objectsOnTile;
        private bool occupiedByBuilding;

        private int tileHeight;

        private SlopeType slopeType;
        private Direction slopeDirection = Direction.None;
        private RotateType texRotate;
        //private GameTexture texture;

        private LandType landType;

        public Tile(DDDCoordinate coord)
        {
            this.coord = coord;
        }

        public Tile(DDDCoordinate coord, LandType landType)
        {
            this.coord = coord;
            this.texRotate = RotateType.Zero;
            //this.texture = tex;
            this.landType = landType;

            //objectsOnTile = new List<GameObject>();
            //CalcTile();
        }

        public int GetCorner(Direction dir)
        {
            return 0;
        }

        public void SetCorner(Direction dir, int height)
        {
            //tileCorners[(int)dir] = height * 2;
            //CalcTile();
        }

        public bool AddGameObject(GameObject obj)
        {
            if(!occupiedByBuilding) {

                if (objectsOnTile == null) objectsOnTile = new List<GameObject>();

                objectsOnTile.Add(obj);

                if (obj is Building) occupiedByBuilding = true;

                return true;
            }
            return false;
        }

        public void RemoveGameObject(GameObject obj)
        {
            objectsOnTile.Remove(obj);

            if (obj is Building) occupiedByBuilding = false;
        }

        public int Height
        {
            get { return tileHeight; }
        }

        private int CalculateHeight(int ne, int se, int sw, int nw)
        {
            int maxH = Math.Max(Math.Max(ne, se), Math.Max(nw, sw));
            int minH = Math.Min(Math.Min(ne, se), Math.Min(nw, sw));

            switch (slopeType)
            {
                case SlopeType.Flat: return ne;
                case SlopeType.FlatSlope:
                    {
                        return (maxH + minH) / 2;
                    }
                case SlopeType.CornerSlope:
                    {
                        foreach (int height in table.Keys)
                        {
                            if (table[height] == 3) return height;
                        }
                        break;
                    }
                case SlopeType.SlantSlope:
                    {
                        return (ne + se + sw + nw) / 4;
                    }
                case SlopeType.DoubleCornerSlope:
                    {
                        return minH;
                    }
            }

            return 0;
        }

        public LandType LandType
        {
            get { return landType; }
            set { landType = value; }
        }

        //public RotateType RotateType
        //{
        //    get { return this.texRotate; }
        //    set { texRotate = value; }
        //}

        public SlopeType SlopeType
        {
            get { return slopeType; }
        }

        public Direction SlopeDirection
        {
            get { return slopeDirection; }
        }

        public DDDCoordinate Coordinate
        {
            get { return coord; }
        }

        public float GetRoadHeight(Vector2 point)
        {
            //if (slopeType == SlopeType.Flat)
            //{
            //    return MaxHeight / Game.heightScale;
            //}
            //else
            //{
            //    Plane tile = Plane.FromPoints(new Vector3(coord.X - 0.5f, tileCorners[(int)Direction.SW], coord.Z - 0.5f),
            //                                    new Vector3(coord.X - 0.5f, tileCorners[(int)Direction.NW], coord.Z + 0.5f),
            //                                        new Vector3(coord.X + 0.5f, tileCorners[(int)Direction.NE], coord.Z + 0.5f));
            //    Vector3 source = new Vector3(point.X, MaxHeight + 1, point.Y);
            //    Vector3 dest = new Vector3(point.X, MinHeight - 1, point.Y);

            //    Vector3 intersect = Plane.IntersectLine(tile, source, dest);

            //    return intersect.Y / Game.heightScale;
            //}

            return 0;
            
        }

        public float GetRoadIncline()
        {
            if (slopeType == SlopeType.Flat)
            {
                return 0;
            }
            else
            {
                return (float)MathHelper.ToDegrees((float)Math.Atan(1 / TTXNAGame.HeightScale));
            }
        }

        public Industry IndustryOnTile
        {
            get
            {
                if (objectsOnTile == null) return null;

                foreach (GameObject go in objectsOnTile)
                {
                    if (go is Industry) return (Industry)go;
                }
                return null;
            }
        }

        public Station StationOnTile
        {
            get {

                if (objectsOnTile == null) return null;

                foreach (GameObject go in objectsOnTile)
                {
                    if (go is Station) return (Station)go;
                }
                return null;
            }
        }

        public bool BuildingOnTile
        {
            get
            {
                bool result = false;

                if (objectsOnTile == null) return false;

                foreach (GameObject go in objectsOnTile)
                {
                    if (go is Building) { result = true; break; }
                }
                return result;
            }
        }

        //public int CalculateTileHeight(int ne, int se, int sw, int nw)
        //{
        //    table.Clear();
        //    int[] array = { ne, se, sw, nw };
        //    int maxheight = int.MinValue;
        //    int maxCorners = 0;

        //    foreach (int height in array)
        //    {

        //        if (table.ContainsKey(height))
        //        {
        //            table[height]++;
        //        }
        //        else { table[height] = 1; }

        //        if (height > maxheight)
        //        {
        //            maxheight = height;
        //            maxCorners = 1;
        //        }
        //        else if (height == maxheight && maxCorners < 3)
        //        {
        //            maxCorners++;
        //        }
        //    }

        //    if (table.Keys.Count == 1)
        //    {
        //        return table[ne];
        //    }
        //    else if (table.Keys.Count == 3)
        //    {
        //        return (table[ne] + table[se] + table[sw] + table[nw]) / 4;
        //    }

        //    return 1;
        //}

        public int CalculateTileHeight(int ne, int se, int sw, int nw)
        {
            table.Clear();
            int[] array = { ne, se, sw, nw };

            int maxheight = -1;
            int minheight = Int32.MaxValue;

            int maxCorners = 0;

            Direction maxDir = Direction.None;
            Direction minDir = Direction.None;

            Direction equalMaxDir = Direction.None;

            int num = 0;

            foreach (int height in array)
            {
                if (table.ContainsKey(height))
                {
                    table[height]++;
                }
                else { table[height] = 1; }

                if (height > maxheight)
                {
                    maxheight = height;
                    maxCorners = 1;
                    maxDir = (Direction)num;
                }
                else if (height == maxheight && maxCorners < 3)
                {
                    maxCorners++;
                    equalMaxDir = (Direction)num;
                }

                if (height < minheight)
                {
                    minDir = (Direction)num;
                }
                num++;
            }

            if (table.Keys.Count == 1)
            {
                slopeType = SlopeType.Flat;
                slopeDirection = Direction.None;
            }
            else if (table.Keys.Count == 3)
            {
                slopeType = SlopeType.SlantSlope;
                slopeDirection = maxDir;
            }
            else
            {


                foreach (int i in table.Values)
                {
                    if (i == 2)
                    {
                        slopeType = SlopeType.FlatSlope;

                        slopeDirection = Util.Util.Combine(maxDir, equalMaxDir);

                        if (slopeDirection == Direction.None)
                        {
                            slopeType = SlopeType.DoubleCornerSlope;
                        }
                    }
                    else
                    {
                        slopeType = SlopeType.CornerSlope;
                        slopeDirection = maxDir;
                    }
                }
            }

            tileHeight = CalculateHeight(ne, se, sw, nw);

            return tileHeight;
        }

        public override string ToString()
        {
            return coord.ToString();
        }

    }
}
